﻿#include "dlt645.h"
#include "meter.h"
#include "concentrator.h"

int add33(__u8 *data, __u8 len)
{
	for(__u8 i = 0; i < len; ++i)
		*data += 0x33;
}

int sub33(__u8 *data, __u8 len)
{
	for(__u8 i = 0; i < len; ++i)
		*data += 0x33;
}

int dlt645_valid_check(void *pdata, int len)
{
	__u8 *p = (__u8*)pdata;
	__u8 chksum = get_cs(p, len-2);

	mem_dump(p, len);

	if(p[0] == 0x68 && p[7] == 0x68 && p[len-1] == 0x16)
		//&& chksum == p[len-2])
		return 0;
	else 
		return 1;
}

// 封装dlt645结构体
void make_dlt645(dlt645 *pdata, __u8 *addr, __u8 funcode,
	__u8 subframe, __u8 responseID, __u8 dir, __u8 di0, __u8 di1, __u8 *data, __u8 len)
{
	pdata->start1 = pdata->start2 = 0x68;
	pdata->end = 0x16;

	memcpy(pdata->addr, addr, 6);

	pdata->control.dc.funcode = funcode;
	pdata->control.dc.subframes = subframe;
	pdata->control.dc.responseID = responseID;
	pdata->control.dc.direction = dir;
	
	pdata->len = 0;
	if(di0 != 0 || di1 !=0) {
		pdata->_data1.with_di.di0 = di0;
		pdata->_data1.with_di.di1 = di1;
		if(data)	{
			memcpy(pdata->_data1.with_di.data, data, len);
			pdata->len = len + 2;
		}
	} else {
		if(data) {
			memcpy(pdata->_data1.raw.data, data, len);
			pdata->len = len;
		}
	}

	pdata->cs = get_cs(&pdata->start1, pdata->_data1.raw.data - &pdata->start1);
	pdata->cs += get_cs(pdata->_data1.raw.data, pdata->len);
}

__u8* dlt6452raw(dlt645 *pdata, __u8 *raw, __u8 *len)
{
	/* copy start1, addr, star2, control, len 1+6+1+1+1=10 */
	memcpy(pdata, raw, 10);

	/* copy data */
	memcpy(pdata->_data1.raw.data, raw + 10, pdata->len);
	raw[10 + pdata->len] = pdata->cs;
	raw[10 + pdata->len + 1] = pdata->end;

	// raw数据长度等于645结构体数据域的长度+12
	*len = pdata->len + 12;

	return raw;
}

/*
电表模拟实现：
1. 读数据
	可对"主站请求帧"响应，返回"从站正常应答"或"异常应答"
	请 求 帧：C=01H L=02H DI0DI1
	正常应答：C=81H/A1H(无/有后续帧) L=02H+M DI0DI1 DATA 
	异常应答：C=C1H L=01H ERR_CODE
2. 读后续数据
	可对"主站请求后续帧"响应，返回“从站正常应答”或“异常应答”
	请 求 帧：C=02H L=02H
	正常应答：C=82H/A2H（无/有后续帧） L=02H+M DI0DI1 DATA
	异常应答：C=C2H L=01H ERR_CODE
3. 重读数据	TODO
4. 写数据
	可对“主站设置数据请求”响应，返回从站“正常”或“异常”应答
	请 求 帧：C=04H L=02H DI0DI1
	正常应答：C=84H L=00H
	异常应答：C=C4H L=01H err_code
5. 广播校时
	可对“主站广播校时请求”响应，不要求应答
	请 求 帧：C=08H L=06H DATA=YYMMDDHHMMSS
*/
int dlt645_receive(dlt645 *p_recv, int len, meter *m, concentrator *c)
{

	return 0;
error:
	return -1;
}

int dlt645_response(dlt645 *p_request, int len, meter *m, concentrator *c)
{
	//是否有后续帧
	int read_time = 0;
	__u8 recvbuf[BUFSIZ] = {0};
	dlt645 *p_response;
	__u8 *zhuzhan_addr = (__u8*)"112233";

	if(dlt645_valid_check(p_request, len) != 0) {
		return -1;
	} 

	if(p_request->control.dc.direction == 0)
		printf("主站发出的命令帧\n");
	else
		printf("从站发出的命令帧\n");
	if(p_request->control.dc.subframes == 0)
		read_time = 2;
	else
		read_time = 1;

	// 如果有数据字段，那么减去0x33
#if 0
	if(p_request->len)
		sub33(p_request->_data1.raw.data, p_request->len);
#endif

	printf("C=%02x\n", p_request->control.C1);
	printf("funcode=%02x\n", p_request->control.dc.funcode);
	printf("subframe=%02x\n", p_request->control.dc.subframes);
	printf("responseID=%02x\n", p_request->control.dc.responseID);
	printf("dir=%02x\n", p_request->control.dc.direction);

	char tmp[256] = {0};
	int zong = 0;	//电量
	switch(p_request->control.dc.funcode) {
	case READ:	//读数据
		p_response = (dlt645*)calloc(sizeof(dlt645), 1);
		zong = m->get_zong();

		make_dlt645(p_response, zhuzhan_addr, p_request->control.dc.funcode,
			p_request->control.dc.subframes, p_request->control.dc.responseID, 1, 
			p_request->_data1.with_di.di0, p_request->_data1.with_di.di1,
			(__u8*)&zong, sizeof(zong));
		
		mem_dump(p_response, sizeof(dlt645));

		p_response->len = 2 + sizeof(zong);

		p_response->cs = get_cs(p_response, sizeof(dlt645) - 2);

		//拷贝数据到发送缓冲
		if(p_request->control.dc.direction == ZHU_CONG) {
			__u8 len;
			dlt6452raw(p_response, m->tx_buf, &len);
		} else {
			__u8 len;
			dlt6452raw(p_response, m->tx_buf, &len);
		}

		mem_dump(p_response, sizeof(dlt645));
		mem_dump(m->tx_buf, len);
		printf("总: %d\n", m->get_zong());

		//return 1;
		exit(1);
		break;
	case READAGAIN:
		break;
	case WRITE_DEV_ADDR:
		__u8 di0, di1;
		__u8 *pdata;
		char str[32];
		pdata = p_request->_data1.raw.data;
		
		sprintf(str, "%02X%02X%02X%02X%02X%02X", 
			pdata[0], pdata[1], pdata[2],
			pdata[3], pdata[4], pdata[5]);

		printf("写MAC\n");
		// 写地址，即表号（MAC）
		m->set_mac(str);
		break;
	case SETTIME:	//广播校时
		printf("设置时间\n");
		if(p_request->len != 0x06)
			printf("非法请求，长度不对！\n");
		else {
			time_t t1;
			t1 = unix_time(p_request->_data1.raw.data);
			printf("%s\n", ctime(&t1));
			mem_dump(p_request->_data1.raw.data, 6);

			m->set_time(t1);
		}
		break;
	}

	return 0;
error:
	return -1;
}
